import * as THREE from '../three.js/build/three.module.js';
import { OrbitControls } from '../three.js/examples/jsm/controls/OrbitControls.js';
import { EffectComposer } from '../three.js/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from '../three.js/examples/jsm/postprocessing/RenderPass.js';
import { UnrealBloomPass } from '../three.js/examples/jsm/postprocessing/UnrealBloomPass.js';
import { FilmPass } from '../three.js/examples/jsm/postprocessing/FilmPass.js';
import { ShaderPass } from '../three.js/examples/jsm/postprocessing/ShaderPass.js';
import { FXAAShader } from '../three.js/examples/jsm/shaders/FXAAShader.js';
import { OutputPass } from '../three.js/examples/jsm/postprocessing/OutputPass.js';
import { RenderPixelatedPass } from '../three.js/examples/jsm/postprocessing/RenderPixelatedPass.js';
import { DotScreenPass } from '../three.js/examples/jsm/postprocessing/DotScreenPass.js';
import { GlitchPass } from '../three.js/examples/jsm/postprocessing/GlitchPass.js';
import { HalftonePass } from '../three.js/examples/jsm/postprocessing/HalftonePass.js';
import { OutlinePass } from '../three.js/examples/jsm/postprocessing/OutlinePass.js';

class PostProcessingDemo {
    constructor() {
        // 基础组件
        this.scene = null;
        this.camera = null;
        this.renderer = null;
        this.controls = null;
        
        // 后处理组件
        this.composer = null;
        this.renderPass = null;
        this.bloomPass = null;
        this.filmPass = null;
        this.colorCorrectionPass = null;
        this.fxaaPass = null;
        this.pixelatedPass = null;
        this.dotScreenPass = null;
        this.glitchPass = null;
        this.halftonePass = null;
        this.outlinePass = null;
        this.outputPass = null;
        
        // 场景对象
        this.meshes = [];
        this.lights = {};
        
        // 控制参数
        this.params = {
            enablePostProcessing: true,
            resolution: 1.0,
            
            // 发光效果
            enableBloom: true,
            bloomStrength: 1.5,
            bloomRadius: 0.4,
            bloomThreshold: 0.85,
            
            // 胶片效果
            enableFilm: false,
            filmNoise: 0.35,
            filmScanline: 0.025,
            filmGrayscale: false,
            
            // 色彩校正
            enableColorCorrection: false,
            brightness: 1.0,
            contrast: 1.0,
            saturation: 1.0,
            
            // 抗锯齿
            enableFXAA: true,
            
            // 像素化效果
            enablePixelated: false,
            pixelSize: 6,
            
            // 点阵屏幕效果
            enableDotScreen: false,
            dotScreenScale: 4,
            dotScreenAngle: 1.57,
            
            // 故障效果
            enableGlitch: false,
            glitchWildness: 0.2,
            
            // 半色调效果
            enableHalftone: false,
            halftoneRadius: 4,
            halftoneRotateR: Math.PI / 12,
            halftoneRotateG: Math.PI / 12 * 2,
            halftoneRotateB: Math.PI / 12 * 3,
            halftoneScatter: 0,
            
            // 轮廓效果
            enableOutline: false,
            outlineEdgeStrength: 3.0,
            outlineEdgeGlow: 0.0,
            outlineEdgeThickness: 1.0,
            outlinePulsePeriod: 0,
            outlineVisibleEdgeColor: new THREE.Color(0xffffff),
            outlineHiddenEdgeColor: new THREE.Color(0x190a05),
            
            // 场景控制
            autoRotate: true,
            rotationSpeed: 0.01
        };
        
        // 性能监控
        this.stats = {
            fps: 60,
            frameTime: 16.7,
            lastTime: performance.now(),
            frameCount: 0
        };
        
        // 通道信息数据
        this.passInfoData = {
            render: {
                name: 'RenderPass',
                description: 'RenderPass 是后处理管道的基础通道，负责将3D场景渲染到纹理缓冲区中，为后续的后处理效果提供输入图像。',
                properties: {
                    enabled: { value: 'true', desc: '是否启用此通道' },
                    needsSwap: { value: 'true', desc: '是否需要交换缓冲区' },
                    clear: { value: 'true', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'false', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    scene: 'Scene',
                    camera: 'PerspectiveCamera'
                },
                usage: {
                    description: 'RenderPass 通常作为后处理链的第一个通道，将场景渲染结果传递给后续的效果通道。',
                    parameters: [
                        'scene: THREE.Scene - 要渲染的3D场景对象',
                        'camera: THREE.Camera - 渲染视角的相机对象（透视相机或正交相机）',
                        'overrideMaterial: THREE.Material - 可选，覆盖场景中所有材质的材质对象',
                        'clearColor: THREE.Color - 可选，清除颜色，默认为null',
                        'clearAlpha: number - 可选，清除透明度，范围0-1，默认为0'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用，默认true',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认true',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，默认false'
                    ],
                    code: [
                        '// 基础用法',
                        'import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";',
                        '',
                        '// 创建渲染通道',
                        'const renderPass = new RenderPass(scene, camera);',
                        '',
                        '// 添加到效果合成器',
                        'composer.addPass(renderPass);',
                        '',
                        '// 高级用法：使用覆盖材质',
                        'const depthMaterial = new THREE.MeshDepthMaterial();',
                        'const depthPass = new RenderPass(scene, camera, depthMaterial);'
                    ]
                }
            },
            bloom: {
                name: 'UnrealBloomPass',
                description: 'UnrealBloomPass 实现了类似虚幻引擎的发光效果，通过模糊高亮区域来创建光晕和发光效果，常用于增强场景的视觉冲击力。',
                properties: {
                    enabled: { value: 'dynamic', desc: '是否启用此通道' },
                    needsSwap: { value: 'true', desc: '是否需要交换缓冲区' },
                    clear: { value: 'false', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'false', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    strength: 'dynamic',
                    radius: 'dynamic',
                    threshold: 'dynamic'
                },
                usage: {
                    description: '通过调整强度、半径和阈值参数来控制发光效果的强弱和范围。',
                    parameters: [
                        'resolution: THREE.Vector2 - 渲染分辨率，影响效果质量和性能',
                        'strength: number - 发光强度，范围0-3，默认1.0，控制发光亮度',
                        'radius: number - 发光半径，范围0-1，默认0.4，控制发光扩散范围',
                        'threshold: number - 发光阈值，范围0-1，默认0.85，决定哪些区域发光'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认true',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，默认false'
                    ],
                    code: [
                        '// 引入模块',
                        'import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass.js";',
                        '',
                        '// 创建发光通道',
                        'const bloomPass = new UnrealBloomPass(',
                        '    new THREE.Vector2(window.innerWidth, window.innerHeight),',
                        '    1.5,    // strength',
                        '    0.4,    // radius', 
                        '    0.85    // threshold',
                        ');',
                        '',
                        '// 添加到效果合成器',
                        'composer.addPass(bloomPass);',
                        '',
                        '// 动态调整参数',
                        'bloomPass.strength = 2.0;',
                        'bloomPass.radius = 0.6;',
                        'bloomPass.threshold = 0.7;'
                    ]
                }
            },
            film: {
                name: 'FilmPass',
                description: 'FilmPass 模拟老式胶片的视觉效果，包括噪点、扫描线和灰度化，为场景添加复古的电影质感。',
                properties: {
                    enabled: { value: 'dynamic', desc: '是否启用此通道' },
                    needsSwap: { value: 'true', desc: '是否需要交换缓冲区' },
                    clear: { value: 'false', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'false', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    noiseIntensity: 'dynamic',
                    scanlinesIntensity: 'dynamic',
                    grayscale: 'dynamic'
                },
                usage: {
                    description: '调整噪点强度、扫描线密度和是否灰度化来控制胶片效果。',
                    parameters: [
                        'noiseIntensity: number - 噪点强度，范围0-1，默认0.35，控制胶片颗粒感',
                        'scanlinesIntensity: number - 扫描线强度，范围0-1，默认0.025，控制扫描线可见度',
                        'scanlinesCount: number - 扫描线数量，默认648，影响扫描线密度',
                        'grayscale: boolean - 是否转为灰度，默认false，控制黑白效果'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认true',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，默认false'
                    ],
                    code: [
                        '// 引入模块',
                        'import { FilmPass } from "three/examples/jsm/postprocessing/FilmPass.js";',
                        '',
                        '// 创建胶片效果通道',
                        'const filmPass = new FilmPass(',
                        '    0.35,   // noiseIntensity',
                        '    0.025,  // scanlinesIntensity',
                        '    648,    // scanlinesCount',
                        '    false   // grayscale',
                        ');',
                        '',
                        '// 添加到效果合成器',
                        'composer.addPass(filmPass);',
                        '',
                        '// 动态调整参数',
                        'filmPass.uniforms.nIntensity.value = 0.5;',
                        'filmPass.uniforms.sIntensity.value = 0.1;',
                        'filmPass.uniforms.grayscale.value = 1;'
                    ]
                }
            },
            color: {
                name: 'ColorCorrectionPass',
                description: '自定义色彩校正通道，通过调整亮度、对比度、饱和度和色调来改善图像的色彩表现，实现不同的视觉风格。',
                properties: {
                    enabled: { value: 'dynamic', desc: '是否启用此通道' },
                    needsSwap: { value: 'true', desc: '是否需要交换缓冲区' },
                    clear: { value: 'false', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'false', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    brightness: 'dynamic',
                    contrast: 'dynamic',
                    saturation: 'dynamic',
                    hue: 'dynamic'
                },
                usage: {
                    description: '通过自定义着色器实现的色彩校正，可以精确控制图像的色彩属性。',
                    parameters: [
                        'brightness: number - 亮度调整，范围-1到1，默认0，负值变暗，正值变亮',
                        'contrast: number - 对比度调整，范围0到3，默认1，小于1降低对比度，大于1增强对比度',
                        'saturation: number - 饱和度调整，范围0到3，默认1，0为灰度，大于1增强色彩',
                        'hue: number - 色调偏移，范围0到360度，默认0，用于色彩偏移效果'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认true',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，默认false'
                    ],
                    code: [
                        '// 引入模块',
                        'import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";',
                        '',
                        '// 自定义色彩校正着色器',
                        'const ColorCorrectionShader = {',
                        '    uniforms: {',
                        '        "tDiffuse": { value: null },',
                        '        "brightness": { value: 0.0 },',
                        '        "contrast": { value: 1.0 },',
                        '        "saturation": { value: 1.0 },',
                        '        "hue": { value: 0.0 }',
                        '    },',
                        '    // ... 着色器代码',
                        '};',
                        '',
                        '// 创建色彩校正通道',
                        'const colorPass = new ShaderPass(ColorCorrectionShader);',
                        '',
                        '// 添加到效果合成器',
                        'composer.addPass(colorPass);',
                        '',
                        '// 调整参数',
                        'colorPass.uniforms.brightness.value = 0.1;',
                        'colorPass.uniforms.contrast.value = 1.2;',
                        'colorPass.uniforms.saturation.value = 1.1;',
                        'colorPass.uniforms.hue.value = 10;'
                    ]
                }
            },
            fxaa: {
                name: 'FXAAPass',
                description: 'FXAA (Fast Approximate Anti-Aliasing) 是一种快速的抗锯齿技术，通过后处理方式平滑图像边缘，减少锯齿现象。',
                properties: {
                    enabled: { value: 'dynamic', desc: '是否启用此通道' },
                    needsSwap: { value: 'true', desc: '是否需要交换缓冲区' },
                    clear: { value: 'false', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'false', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    resolution: 'Vector2'
                },
                usage: {
                    description: 'FXAA通过分析像素边缘来进行抗锯齿处理，性能开销较小。',
                    parameters: [
                        'resolution: Vector2 - 屏幕分辨率的倒数，用于像素采样计算，必须设置为(1/width, 1/height)'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认true',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，默认false'
                    ],
                    code: [
                        '// 引入模块',
                        'import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";',
                        'import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader.js";',
                        '',
                        '// 创建FXAA抗锯齿通道',
                        'const fxaaPass = new ShaderPass(FXAAShader);',
                        '',
                        '// 设置分辨率参数（必须）',
                        'const width = window.innerWidth;',
                        'const height = window.innerHeight;',
                        'fxaaPass.uniforms.resolution.value.set(1/width, 1/height);',
                        '',
                        '// 添加到效果合成器',
                        'composer.addPass(fxaaPass);',
                        '',
                        '// 窗口大小改变时更新分辨率',
                        'function onWindowResize() {',
                        '    const newWidth = window.innerWidth;',
                        '    const newHeight = window.innerHeight;',
                        '    fxaaPass.uniforms.resolution.value.set(1/newWidth, 1/newHeight);',
                        '}'
                    ]
                }
            },
            pixelated: {
                name: 'RenderPixelatedPass',
                description: 'RenderPixelatedPass 创建像素化效果，将图像分解为较大的像素块，产生复古的8位游戏风格视觉效果。',
                properties: {
                    enabled: { value: 'dynamic', desc: '是否启用此通道' },
                    needsSwap: { value: 'true', desc: '是否需要交换缓冲区' },
                    clear: { value: 'false', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'false', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    pixelSize: 'dynamic',
                    normalEdgeStrength: '0.3',
                    depthEdgeStrength: '0.4'
                },
                usage: {
                    description: '通过调整像素大小来控制像素化程度，数值越大像素块越大。',
                    parameters: [
                        'pixelSize: number - 像素块大小，范围1-32，默认6，数值越大像素块越大',
                        'normalEdgeStrength: number - 法线边缘强度，范围0-2，默认0.3，用于增强物体轮廓',
                        'depthEdgeStrength: number - 深度边缘强度，范围0-2，默认0.4，用于增强深度变化的边缘'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认true',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，默认false'
                    ],
                    code: [
                        '// 引入模块',
                        'import { RenderPixelatedPass } from "three/examples/jsm/postprocessing/RenderPixelatedPass.js";',
                        '',
                        '// 创建像素化通道',
                        'const pixelSize = 6;',
                        'const pixelatedPass = new RenderPixelatedPass(pixelSize, scene, camera);',
                        '',
                        '// 设置边缘检测参数',
                        'pixelatedPass.normalEdgeStrength = 0.3;',
                        'pixelatedPass.depthEdgeStrength = 0.4;',
                        '',
                        '// 添加到效果合成器',
                        'composer.addPass(pixelatedPass);',
                        '',
                        '// 动态调整像素大小',
                        'function setPixelSize(size) {',
                        '    pixelatedPass.setPixelSize(size);',
                        '}'
                    ]
                }
            },
            dotscreen: {
                name: 'DotScreenPass',
                description: 'DotScreenPass 模拟点阵屏幕效果，将图像转换为由圆点组成的图案，类似于老式印刷或显示器的效果。',
                properties: {
                    enabled: { value: 'dynamic', desc: '是否启用此通道' },
                    needsSwap: { value: 'true', desc: '是否需要交换缓冲区' },
                    clear: { value: 'false', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'false', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    scale: 'dynamic',
                    angle: 'dynamic',
                    center: 'Vector2(0.5, 0.5)'
                },
                usage: {
                    description: '调整缩放和角度参数来控制点阵的大小和方向。',
                    parameters: [
                        'center: Vector2 - 点阵中心位置，默认(0.5, 0.5)，范围0-1，控制点阵图案的中心点',
                        'angle: number - 点阵旋转角度，单位弧度，默认1.57，控制点阵的方向',
                        'scale: number - 点阵缩放比例，范围0.1-5，默认1，数值越大点越稀疏'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认true',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，默认false'
                    ],
                    code: [
                        '// 引入模块',
                        'import { DotScreenPass } from "three/examples/jsm/postprocessing/DotScreenPass.js";',
                        'import * as THREE from "three";',
                        '',
                        '// 创建点阵屏幕通道',
                        'const center = new THREE.Vector2(0.5, 0.5);',
                        'const angle = Math.PI / 2;',
                        'const scale = 1.0;',
                        'const dotScreenPass = new DotScreenPass(center, angle, scale);',
                        '',
                        '// 添加到效果合成器',
                        'composer.addPass(dotScreenPass);',
                        '',
                        '// 动态调整参数',
                        'dotScreenPass.uniforms.center.value.set(0.5, 0.5);',
                        'dotScreenPass.uniforms.angle.value = Math.PI / 4;',
                        'dotScreenPass.uniforms.scale.value = 1.5;'
                    ]
                }
            },
            glitch: {
                name: 'GlitchPass',
                description: 'GlitchPass 创建数字故障效果，模拟电子设备故障时的视觉干扰，包括颜色偏移、扫描线和随机噪点。',
                properties: {
                    enabled: { value: 'dynamic', desc: '是否启用此通道' },
                    needsSwap: { value: 'true', desc: '是否需要交换缓冲区' },
                    clear: { value: 'false', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'false', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    wildness: 'dynamic',
                    dtSize: '64',
                    goWild: 'false'
                },
                usage: {
                    description: '通过wildness参数控制故障效果的强度，数值越高故障越明显。',
                    parameters: [
                        'dtSize: number - 数据纹理大小，默认64，影响故障效果的精细度',
                        'wildness: number - 故障强度，范围0-1，默认0.2，控制故障效果的激烈程度',
                        'goWild: boolean - 疯狂模式，默认false，开启后产生更强烈的故障效果'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认true',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，默认false'
                    ],
                    code: [
                        '// 引入模块',
                        'import { GlitchPass } from "three/examples/jsm/postprocessing/GlitchPass.js";',
                        '',
                        '// 创建故障效果通道',
                        'const dtSize = 64;',
                        'const glitchPass = new GlitchPass(dtSize);',
                        '',
                        '// 设置故障参数',
                        'glitchPass.uniforms.wildness.value = 0.2;',
                        'glitchPass.goWild = false;',
                        '',
                        '// 添加到效果合成器',
                        'composer.addPass(glitchPass);',
                        '',
                        '// 动态控制故障效果',
                        'function triggerGlitch() {',
                        '    glitchPass.goWild = true;',
                        '    setTimeout(() => {',
                        '        glitchPass.goWild = false;',
                        '    }, 100);',
                        '}'
                    ]
                }
            },
            halftone: {
                name: 'HalftonePass',
                description: 'HalftonePass 实现半色调效果，将图像转换为由不同大小的点组成的图案，模拟传统印刷的半色调技术。',
                properties: {
                    enabled: { value: 'dynamic', desc: '是否启用此通道' },
                    needsSwap: { value: 'true', desc: '是否需要交换缓冲区' },
                    clear: { value: 'false', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'false', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    radius: 'dynamic',
                    rotateR: 'Math.PI/12',
                    rotateG: 'Math.PI/12*2',
                    rotateB: 'Math.PI/12*3',
                    scatter: 'dynamic'
                },
                usage: {
                    description: '调整半径和散射参数来控制半色调点的大小和分布。',
                    parameters: [
                        'width: number - 渲染目标宽度，通常设置为画布宽度',
                        'height: number - 渲染目标高度，通常设置为画布高度',
                        'radius: number - 半色调点半径，范围1-25，默认4，控制点的大小',
                        'rotateR: number - 红色通道旋转角度，默认Math.PI/12，用于避免摩尔纹',
                        'rotateG: number - 绿色通道旋转角度，默认Math.PI/12*2，用于避免摩尔纹',
                        'rotateB: number - 蓝色通道旋转角度，默认Math.PI/12*3，用于避免摩尔纹',
                        'scatter: number - 点的散射程度，范围0-1，默认0，增加点的随机性'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认true',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，默认false'
                    ],
                    code: [
                        '// 引入模块',
                        'import { HalftonePass } from "three/examples/jsm/postprocessing/HalftonePass.js";',
                        '',
                        '// 创建半色调通道',
                        'const width = window.innerWidth;',
                        'const height = window.innerHeight;',
                        'const params = {',
                        '    radius: 4,',
                        '    rotateR: Math.PI / 12,',
                        '    rotateG: Math.PI / 12 * 2,',
                        '    rotateB: Math.PI / 12 * 3,',
                        '    scatter: 0',
                        '};',
                        'const halftonePass = new HalftonePass(width, height, params);',
                        '',
                        '// 添加到效果合成器',
                        'composer.addPass(halftonePass);',
                        '',
                        '// 动态调整参数',
                        'halftonePass.uniforms.radius.value = 6;',
                        'halftonePass.uniforms.scatter.value = 0.5;'
                    ]
                }
            },
            outline: {
                name: 'OutlinePass',
                description: 'OutlinePass 为选定的对象添加轮廓效果，可以突出显示重要的几何体，常用于选择高亮和视觉强调。',
                properties: {
                    enabled: { value: 'dynamic', desc: '是否启用此通道' },
                    needsSwap: { value: 'true', desc: '是否需要交换缓冲区' },
                    clear: { value: 'false', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'false', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    edgeStrength: 'dynamic',
                    edgeGlow: 'dynamic',
                    edgeThickness: 'dynamic',
                    pulsePeriod: 'dynamic',
                    visibleEdgeColor: 'dynamic',
                    hiddenEdgeColor: 'dynamic'
                },
                usage: {
                    description: '调整边缘强度、发光、厚度等参数来控制轮廓效果的外观。',
                    parameters: [
                        'resolution: Vector2 - 渲染分辨率，通常设置为(width, height)',
                        'scene: Scene - 需要渲染轮廓的场景对象',
                        'camera: Camera - 渲染使用的相机对象',
                        'edgeStrength: number - 边缘强度，范围0-10，默认3，控制轮廓线的强度',
                        'edgeGlow: number - 边缘发光，范围0-1，默认0，增加轮廓的发光效果',
                        'edgeThickness: number - 边缘厚度，范围1-4，默认1，控制轮廓线粗细',
                        'pulsePeriod: number - 脉冲周期，范围0-5，默认0，创建呼吸灯效果',
                        'visibleEdgeColor: Color - 可见边缘颜色，默认白色，设置可见部分轮廓颜色',
                        'hiddenEdgeColor: Color - 隐藏边缘颜色，默认白色，设置被遮挡部分轮廓颜色'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认true',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，默认false',
                        'selectedObjects: Array - 需要添加轮廓的对象数组'
                    ],
                    code: [
                        '// 引入模块',
                        'import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";',
                        'import * as THREE from "three";',
                        '',
                        '// 创建轮廓通道',
                        'const resolution = new THREE.Vector2(window.innerWidth, window.innerHeight);',
                        'const outlinePass = new OutlinePass(resolution, scene, camera);',
                        '',
                        '// 设置轮廓参数',
                        'outlinePass.edgeStrength = 3;',
                        'outlinePass.edgeGlow = 0.5;',
                        'outlinePass.edgeThickness = 1;',
                        'outlinePass.pulsePeriod = 2;',
                        'outlinePass.visibleEdgeColor.set("#ffffff");',
                        'outlinePass.hiddenEdgeColor.set("#190a05");',
                        '',
                        '// 设置需要轮廓的对象',
                        'outlinePass.selectedObjects = [mesh1, mesh2];',
                        '',
                        '// 添加到效果合成器',
                        'composer.addPass(outlinePass);'
                    ]
                }
            },
            output: {
                name: 'OutputPass',
                description: 'OutputPass 是后处理管道的最终输出通道，负责将处理后的图像渲染到屏幕上，确保正确的颜色空间和伽马校正。',
                properties: {
                    enabled: { value: 'true', desc: '是否启用此通道' },
                    needsSwap: { value: 'false', desc: '是否需要交换缓冲区' },
                    clear: { value: 'false', desc: '渲染前是否清除缓冲区' },
                    renderToScreen: { value: 'true', desc: '是否直接渲染到屏幕' }
                },
                parameters: {
                    toneMapping: 'ACESFilmicToneMapping',
                    outputEncoding: 'sRGBEncoding'
                },
                usage: {
                    description: 'OutputPass确保最终图像以正确的格式显示在屏幕上。',
                    parameters: [
                        'toneMapping: number - 色调映射类型，如THREE.ACESFilmicToneMapping，用于HDR到LDR转换',
                        'outputEncoding: number - 输出编码格式，如THREE.sRGBEncoding，确保正确的颜色空间'
                    ],
                    properties: [
                        'enabled: boolean - 控制通道是否启用，通常为true',
                        'needsSwap: boolean - 是否需要交换读写缓冲区，默认false',
                        'clear: boolean - 渲染前是否清除缓冲区，默认false',
                        'renderToScreen: boolean - 是否直接渲染到屏幕，必须为true'
                    ],
                    code: [
                        '// 引入模块',
                        'import { OutputPass } from "three/examples/jsm/postprocessing/OutputPass.js";',
                        'import * as THREE from "three";',
                        '',
                        '// 创建输出通道（必须是最后一个通道）',
                        'const outputPass = new OutputPass();',
                        '',
                        '// 设置色调映射（可选）',
                        'renderer.toneMapping = THREE.ACESFilmicToneMapping;',
                        'renderer.toneMappingExposure = 1.0;',
                        '',
                        '// 设置输出编码（可选）',
                        'renderer.outputEncoding = THREE.sRGBEncoding;',
                        '',
                        '// 添加到效果合成器（必须是最后一个）',
                        'composer.addPass(outputPass);',
                        '',
                        '// 注意：OutputPass必须是效果链中的最后一个通道',
                        '// 不要在OutputPass之后添加任何其他效果'
                    ]
                }
            }
        };
        
        this.currentSelectedPass = 'render';
        
        this.init();
    }
    
    init() {
        this.createScene();
        this.createLights();
        this.createGeometry();
        this.setupPostProcessing();
        this.setupEventListeners();
        this.setupPassInfoListeners();
        this.updateEffectChain();
        this.updatePassInfo('render');
        this.animate();
    }
    
    createScene() {
        // 创建场景
        this.scene = new THREE.Scene();
        this.scene.background = new THREE.Color(0x0a0a0a);
        this.scene.fog = new THREE.Fog(0x0a0a0a, 50, 200);
        
        // 创建相机
        this.camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
        );
        this.camera.position.set(0, 5, 15);
        
        // 创建渲染器
        this.renderer = new THREE.WebGLRenderer({ 
            antialias: false, // 关闭内置抗锯齿，使用后处理FXAA
            powerPreference: 'high-performance'
        });
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
        this.renderer.shadowMap.enabled = true;
        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
        this.renderer.toneMappingExposure = 1.0;
        
        document.querySelector('.canvas-container').appendChild(this.renderer.domElement);
        
        // 创建控制器
        this.controls = new OrbitControls(this.camera, this.renderer.domElement);
        this.controls.enableDamping = true;
        this.controls.dampingFactor = 0.05;
        this.controls.maxDistance = 50;
        this.controls.minDistance = 5;
    }
    
    createLights() {
        // 环境光
        this.lights.ambient = new THREE.AmbientLight(0x404040, 0.3);
        this.scene.add(this.lights.ambient);
        
        // 主方向光
        this.lights.directional = new THREE.DirectionalLight(0xffffff, 1.0);
        this.lights.directional.position.set(10, 10, 5);
        this.lights.directional.castShadow = true;
        this.lights.directional.shadow.mapSize.width = 2048;
        this.lights.directional.shadow.mapSize.height = 2048;
        this.lights.directional.shadow.camera.near = 0.5;
        this.lights.directional.shadow.camera.far = 50;
        this.lights.directional.shadow.camera.left = -20;
        this.lights.directional.shadow.camera.right = 20;
        this.lights.directional.shadow.camera.top = 20;
        this.lights.directional.shadow.camera.bottom = -20;
        this.scene.add(this.lights.directional);
        
        // 彩色点光源（用于发光效果）
        const colors = [0xff0040, 0x0040ff, 0x40ff00, 0xff4000, 0x4000ff];
        this.lights.points = [];
        
        for (let i = 0; i < 5; i++) {
            const light = new THREE.PointLight(colors[i], 2, 30);
            const angle = (i / 5) * Math.PI * 2;
            light.position.set(
                Math.cos(angle) * 8,
                Math.sin(i * 0.5) * 3 + 2,
                Math.sin(angle) * 8
            );
            this.lights.points.push(light);
            this.scene.add(light);
            
            // 添加光源可视化
            const sphereGeometry = new THREE.SphereGeometry(0.2, 16, 8);
            const sphereMaterial = new THREE.MeshBasicMaterial({ 
                color: colors[i],
                transparent: true,
                opacity: 0.8
            });
            const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
            sphere.position.copy(light.position);
            this.scene.add(sphere);
        }
    }
    
    createGeometry() {
        // 创建地面
        const groundGeometry = new THREE.PlaneGeometry(50, 50);
        const groundMaterial = new THREE.MeshLambertMaterial({ 
            color: 0x333333,
            transparent: true,
            opacity: 0.8
        });
        const ground = new THREE.Mesh(groundGeometry, groundMaterial);
        ground.rotation.x = -Math.PI / 2;
        ground.receiveShadow = true;
        this.scene.add(ground);
        
        // 创建多个几何体
        const geometries = [
            new THREE.BoxGeometry(2, 2, 2),
            new THREE.SphereGeometry(1.2, 32, 16),
            new THREE.ConeGeometry(1, 2, 8),
            new THREE.TorusGeometry(1, 0.4, 16, 100),
            new THREE.OctahedronGeometry(1.5)
        ];
        
        const materials = [
            new THREE.MeshPhongMaterial({ color: 0xff6b6b, shininess: 100 }),
            new THREE.MeshPhongMaterial({ color: 0x4ecdc4, shininess: 100 }),
            new THREE.MeshPhongMaterial({ color: 0x45b7d1, shininess: 100 }),
            new THREE.MeshPhongMaterial({ color: 0xf9ca24, shininess: 100 }),
            new THREE.MeshPhongMaterial({ color: 0x6c5ce7, shininess: 100 })
        ];
        
        for (let i = 0; i < 5; i++) {
            const mesh = new THREE.Mesh(geometries[i], materials[i]);
            const angle = (i / 5) * Math.PI * 2;
            mesh.position.set(
                Math.cos(angle) * 6,
                1 + Math.sin(i) * 0.5,
                Math.sin(angle) * 6
            );
            mesh.castShadow = true;
            mesh.receiveShadow = true;
            this.meshes.push(mesh);
            this.scene.add(mesh);
        }
        
        // 创建发光物体
        const emissiveGeometry = new THREE.IcosahedronGeometry(0.5, 1);
        const emissiveMaterial = new THREE.MeshBasicMaterial({ 
            color: 0xffffff,
            transparent: true,
            opacity: 0.9
        });
        
        for (let i = 0; i < 8; i++) {
            const mesh = new THREE.Mesh(emissiveGeometry, emissiveMaterial.clone());
            mesh.material.color.setHSL(i / 8, 1, 0.5);
            const angle = (i / 8) * Math.PI * 2;
            mesh.position.set(
                Math.cos(angle) * 12,
                3 + Math.sin(i * 2) * 2,
                Math.sin(angle) * 12
            );
            this.meshes.push(mesh);
            this.scene.add(mesh);
        }
    }
    
    setupPostProcessing() {
        // 创建效果合成器
        this.composer = new EffectComposer(this.renderer);
        
        // 1. 基础渲染通道
        this.renderPass = new RenderPass(this.scene, this.camera);
        this.composer.addPass(this.renderPass);
        
        // 2. 发光通道
        this.bloomPass = new UnrealBloomPass(
            new THREE.Vector2(window.innerWidth, window.innerHeight),
            this.params.bloomStrength,
            this.params.bloomRadius,
            this.params.bloomThreshold
        );
        this.composer.addPass(this.bloomPass);
        
        // 3. 胶片效果通道
        this.filmPass = new FilmPass(
            this.params.filmNoise,
            this.params.filmScanline,
            648,
            this.params.filmGrayscale
        );
        this.filmPass.enabled = this.params.enableFilm;
        this.composer.addPass(this.filmPass);
        
        // 4. 色彩校正通道
        this.createColorCorrectionPass();
        
        // 5. 像素化通道
        this.pixelatedPass = new RenderPixelatedPass(
            this.params.pixelSize,
            this.scene,
            this.camera
        );
        this.pixelatedPass.enabled = this.params.enablePixelated;
        this.composer.addPass(this.pixelatedPass);
        
        // 6. 点阵屏幕通道
        this.dotScreenPass = new DotScreenPass(
            new THREE.Vector2(0.5, 0.5),
            this.params.dotScreenAngle,
            this.params.dotScreenScale
        );
        this.dotScreenPass.enabled = this.params.enableDotScreen;
        this.composer.addPass(this.dotScreenPass);
        
        // 7. 故障效果通道
        this.glitchPass = new GlitchPass();
        this.glitchPass.enabled = this.params.enableGlitch;
        this.composer.addPass(this.glitchPass);
        
        // 8. 半色调通道
        this.halftonePass = new HalftonePass(
            window.innerWidth,
            window.innerHeight,
            {
                radius: this.params.halftoneRadius,
                rotateR: this.params.halftoneRotateR,
                rotateG: this.params.halftoneRotateG,
                rotateB: this.params.halftoneRotateB,
                scatter: this.params.halftoneScatter
            }
        );
        this.halftonePass.enabled = this.params.enableHalftone;
        this.composer.addPass(this.halftonePass);
        
        // 9. 轮廓通道
        this.outlinePass = new OutlinePass(
            new THREE.Vector2(window.innerWidth, window.innerHeight),
            this.scene,
            this.camera
        );
        this.outlinePass.enabled = this.params.enableOutline;
        this.outlinePass.edgeStrength = this.params.outlineEdgeStrength;
        this.outlinePass.edgeGlow = this.params.outlineEdgeGlow;
        this.outlinePass.edgeThickness = this.params.outlineEdgeThickness;
        this.outlinePass.pulsePeriod = this.params.outlinePulsePeriod;
        this.outlinePass.visibleEdgeColor.copy(this.params.outlineVisibleEdgeColor);
        this.outlinePass.hiddenEdgeColor.copy(this.params.outlineHiddenEdgeColor);
        // 默认选择所有网格对象进行轮廓显示
        this.outlinePass.selectedObjects = this.meshes;
        this.composer.addPass(this.outlinePass);
        
        // 10. FXAA抗锯齿通道
        this.fxaaPass = new ShaderPass(FXAAShader);
        this.fxaaPass.uniforms['resolution'].value.set(
            1 / window.innerWidth, 
            1 / window.innerHeight
        );
        this.composer.addPass(this.fxaaPass);
        
        // 11. 输出通道
        this.outputPass = new OutputPass();
        this.composer.addPass(this.outputPass);
    }
    
    createColorCorrectionPass() {
        const colorCorrectionShader = {
            uniforms: {
                tDiffuse: { value: null },
                brightness: { value: this.params.brightness },
                contrast: { value: this.params.contrast },
                saturation: { value: this.params.saturation }
            },
            vertexShader: `
                varying vec2 vUv;
                void main() {
                    vUv = uv;
                    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                }
            `,
            fragmentShader: `
                uniform sampler2D tDiffuse;
                uniform float brightness;
                uniform float contrast;
                uniform float saturation;
                varying vec2 vUv;
                
                vec3 adjustBrightness(vec3 color, float brightness) {
                    return color * brightness;
                }
                
                vec3 adjustContrast(vec3 color, float contrast) {
                    return (color - 0.5) * contrast + 0.5;
                }
                
                vec3 adjustSaturation(vec3 color, float saturation) {
                    float gray = dot(color, vec3(0.299, 0.587, 0.114));
                    return mix(vec3(gray), color, saturation);
                }
                
                void main() {
                    vec4 texel = texture2D(tDiffuse, vUv);
                    vec3 color = texel.rgb;
                    
                    color = adjustBrightness(color, brightness);
                    color = adjustContrast(color, contrast);
                    color = adjustSaturation(color, saturation);
                    
                    gl_FragColor = vec4(color, texel.a);
                }
            `
        };
        
        this.colorCorrectionPass = new ShaderPass(colorCorrectionShader);
        this.colorCorrectionPass.enabled = this.params.enableColorCorrection;
        this.composer.addPass(this.colorCorrectionPass);
    }
    
    setupEventListeners() {
        // 窗口大小调整
        window.addEventListener('resize', () => this.onWindowResize());
        
        // 基础设置控制
        document.getElementById('enablePostProcessing').addEventListener('change', (e) => {
            this.params.enablePostProcessing = e.target.checked;
        });
        
        document.getElementById('resolution').addEventListener('change', (e) => {
            this.params.resolution = parseFloat(e.target.value);
            this.updateResolution();
        });
        
        // 发光效果控制
        this.setupBloomControls();
        
        // 胶片效果控制
        this.setupFilmControls();
        
        // 色彩校正控制
        this.setupColorCorrectionControls();
        
        // 像素化效果控制
        this.setupPixelatedControls();
        
        // 点阵屏幕效果控制
        this.setupDotScreenControls();
        
        // 故障效果控制
        this.setupGlitchControls();
        
        // 半色调效果控制
        this.setupHalftoneControls();
        
        // 轮廓效果控制
        this.setupOutlineControls();
        
        // FXAA控制
        document.getElementById('enableFXAA').addEventListener('change', (e) => {
            this.params.enableFXAA = e.target.checked;
            this.fxaaPass.enabled = this.params.enableFXAA;
            this.updateEffectChain();
        });
        
        // 场景控制
        document.getElementById('autoRotate').addEventListener('change', (e) => {
            this.params.autoRotate = e.target.checked;
        });
        
        document.getElementById('rotationSpeed').addEventListener('input', (e) => {
            this.params.rotationSpeed = parseFloat(e.target.value);
            document.getElementById('rotationSpeedValue').textContent = e.target.value;
        });
        
        // 重置按钮
        document.getElementById('resetCamera').addEventListener('click', () => {
            this.camera.position.set(0, 5, 15);
            this.controls.reset();
        });
        
        document.getElementById('resetEffects').addEventListener('click', () => {
            this.resetAllEffects();
        });
    }
    
    setupBloomControls() {
        document.getElementById('enableBloom').addEventListener('change', (e) => {
            this.params.enableBloom = e.target.checked;
            this.bloomPass.enabled = this.params.enableBloom;
            this.updateEffectChain();
        });
        
        document.getElementById('bloomStrength').addEventListener('input', (e) => {
            this.params.bloomStrength = parseFloat(e.target.value);
            this.bloomPass.strength = this.params.bloomStrength;
            document.getElementById('bloomStrengthValue').textContent = e.target.value;
        });
        
        document.getElementById('bloomRadius').addEventListener('input', (e) => {
            this.params.bloomRadius = parseFloat(e.target.value);
            this.bloomPass.radius = this.params.bloomRadius;
            document.getElementById('bloomRadiusValue').textContent = e.target.value;
        });
        
        document.getElementById('bloomThreshold').addEventListener('input', (e) => {
            this.params.bloomThreshold = parseFloat(e.target.value);
            this.bloomPass.threshold = this.params.bloomThreshold;
            document.getElementById('bloomThresholdValue').textContent = e.target.value;
        });
    }
    
    setupFilmControls() {
        document.getElementById('enableFilm').addEventListener('change', (e) => {
            this.params.enableFilm = e.target.checked;
            this.filmPass.enabled = this.params.enableFilm;
            this.updateEffectChain();
        });
        
        document.getElementById('filmNoise').addEventListener('input', (e) => {
            this.params.filmNoise = parseFloat(e.target.value);
            this.filmPass.uniforms.nIntensity.value = this.params.filmNoise;
            document.getElementById('filmNoiseValue').textContent = e.target.value;
        });
        
        document.getElementById('filmScanline').addEventListener('input', (e) => {
            this.params.filmScanline = parseFloat(e.target.value);
            this.filmPass.uniforms.sIntensity.value = this.params.filmScanline;
            document.getElementById('filmScanlineValue').textContent = e.target.value;
        });
        
        document.getElementById('filmGrayscale').addEventListener('change', (e) => {
            this.params.filmGrayscale = e.target.checked;
            this.filmPass.uniforms.grayscale.value = this.params.filmGrayscale;
        });
    }
    
    setupColorCorrectionControls() {
        document.getElementById('enableColorCorrection').addEventListener('change', (e) => {
            this.params.enableColorCorrection = e.target.checked;
            this.colorCorrectionPass.enabled = this.params.enableColorCorrection;
            this.updateEffectChain();
        });
        
        document.getElementById('brightness').addEventListener('input', (e) => {
            this.params.brightness = parseFloat(e.target.value);
            this.colorCorrectionPass.uniforms.brightness.value = this.params.brightness;
            document.getElementById('brightnessValue').textContent = e.target.value;
        });
        
        document.getElementById('contrast').addEventListener('input', (e) => {
            this.params.contrast = parseFloat(e.target.value);
            this.colorCorrectionPass.uniforms.contrast.value = this.params.contrast;
            document.getElementById('contrastValue').textContent = e.target.value;
        });
        
        document.getElementById('saturation').addEventListener('input', (e) => {
            this.params.saturation = parseFloat(e.target.value);
            this.colorCorrectionPass.uniforms.saturation.value = this.params.saturation;
            document.getElementById('saturationValue').textContent = e.target.value;
        });
    }
    
    setupPixelatedControls() {
        document.getElementById('enablePixelated').addEventListener('change', (e) => {
            this.params.enablePixelated = e.target.checked;
            this.pixelatedPass.enabled = this.params.enablePixelated;
            this.updateEffectChain();
        });
        
        document.getElementById('pixelSize').addEventListener('input', (e) => {
            this.params.pixelSize = parseInt(e.target.value);
            this.pixelatedPass.setPixelSize(this.params.pixelSize);
            document.getElementById('pixelSizeValue').textContent = e.target.value;
        });
    }
    
    setupDotScreenControls() {
        document.getElementById('enableDotScreen').addEventListener('change', (e) => {
            this.params.enableDotScreen = e.target.checked;
            this.dotScreenPass.enabled = this.params.enableDotScreen;
            this.updateEffectChain();
        });
        
        document.getElementById('dotScreenScale').addEventListener('input', (e) => {
            this.params.dotScreenScale = parseFloat(e.target.value);
            this.dotScreenPass.uniforms.scale.value = this.params.dotScreenScale;
            document.getElementById('dotScreenScaleValue').textContent = parseFloat(e.target.value).toFixed(1);
        });
        
        document.getElementById('dotScreenAngle').addEventListener('input', (e) => {
            this.params.dotScreenAngle = parseFloat(e.target.value);
            this.dotScreenPass.uniforms.angle.value = this.params.dotScreenAngle;
            document.getElementById('dotScreenAngleValue').textContent = parseFloat(e.target.value).toFixed(2);
        });
    }
    
    setupGlitchControls() {
        document.getElementById('enableGlitch').addEventListener('change', (e) => {
            this.params.enableGlitch = e.target.checked;
            this.glitchPass.enabled = this.params.enableGlitch;
            this.updateEffectChain();
        });
        
        document.getElementById('glitchWildness').addEventListener('input', (e) => {
            this.params.glitchWildness = parseFloat(e.target.value);
            // Note: Standard GlitchPass doesn't have wildness uniform
            if (this.glitchPass.uniforms && this.glitchPass.uniforms.wildness) {
                this.glitchPass.uniforms.wildness.value = this.params.glitchWildness;
            }
            document.getElementById('glitchWildnessValue').textContent = parseFloat(e.target.value).toFixed(2);
        });
    }
    
    setupHalftoneControls() {
        document.getElementById('enableHalftone').addEventListener('change', (e) => {
            this.params.enableHalftone = e.target.checked;
            this.halftonePass.enabled = this.params.enableHalftone;
            this.updateEffectChain();
        });
        
        document.getElementById('halftoneRadius').addEventListener('input', (e) => {
            this.params.halftoneRadius = parseFloat(e.target.value);
            this.halftonePass.uniforms.radius.value = this.params.halftoneRadius;
            document.getElementById('halftoneRadiusValue').textContent = parseFloat(e.target.value).toFixed(1);
        });
        
        document.getElementById('halftoneScatter').addEventListener('input', (e) => {
            this.params.halftoneScatter = parseFloat(e.target.value);
            this.halftonePass.uniforms.scatter.value = this.params.halftoneScatter;
            document.getElementById('halftoneScatterValue').textContent = parseFloat(e.target.value).toFixed(2);
        });
    }
    
    setupOutlineControls() {
        document.getElementById('enableOutline').addEventListener('change', (e) => {
            this.params.enableOutline = e.target.checked;
            this.outlinePass.enabled = this.params.enableOutline;
            this.updateEffectChain();
        });
        
        document.getElementById('outlineEdgeStrength').addEventListener('input', (e) => {
            this.params.outlineEdgeStrength = parseFloat(e.target.value);
            this.outlinePass.edgeStrength = this.params.outlineEdgeStrength;
            document.getElementById('outlineEdgeStrengthValue').textContent = parseFloat(e.target.value).toFixed(1);
        });
        
        document.getElementById('outlineEdgeGlow').addEventListener('input', (e) => {
            this.params.outlineEdgeGlow = parseFloat(e.target.value);
            this.outlinePass.edgeGlow = this.params.outlineEdgeGlow;
            document.getElementById('outlineEdgeGlowValue').textContent = parseFloat(e.target.value).toFixed(1);
        });
        
        document.getElementById('outlineEdgeThickness').addEventListener('input', (e) => {
            this.params.outlineEdgeThickness = parseFloat(e.target.value);
            this.outlinePass.edgeThickness = this.params.outlineEdgeThickness;
            document.getElementById('outlineEdgeThicknessValue').textContent = parseFloat(e.target.value).toFixed(1);
        });
        
        document.getElementById('outlinePulsePeriod').addEventListener('input', (e) => {
            this.params.outlinePulsePeriod = parseFloat(e.target.value);
            this.outlinePass.pulsePeriod = this.params.outlinePulsePeriod;
            document.getElementById('outlinePulsePeriodValue').textContent = parseFloat(e.target.value).toFixed(1);
        });
        
        document.getElementById('outlineVisibleEdgeColor').addEventListener('input', (e) => {
            const hexValue = parseInt(e.target.value.replace('#', ''), 16);
            this.params.outlineVisibleEdgeColor.setHex(hexValue);
            this.outlinePass.visibleEdgeColor.setHex(hexValue);
        });
        
        document.getElementById('outlineHiddenEdgeColor').addEventListener('input', (e) => {
            const hexValue = parseInt(e.target.value.replace('#', ''), 16);
            this.params.outlineHiddenEdgeColor.setHex(hexValue);
            this.outlinePass.hiddenEdgeColor.setHex(hexValue);
        });
    }
    
    updateEffectChain() {
        const effectItems = document.querySelectorAll('.effect-item');
        
        effectItems.forEach(item => {
            const effect = item.dataset.effect;
            let isActive = false;
            
            switch (effect) {
                case 'render':
                    isActive = true; // 总是激活
                    break;
                case 'bloom':
                    isActive = this.params.enableBloom;
                    break;
                case 'film':
                    isActive = this.params.enableFilm;
                    break;
                case 'color':
                    isActive = this.params.enableColorCorrection;
                    break;
                case 'pixelated':
                    isActive = this.params.enablePixelated;
                    break;
                case 'dotscreen':
                    isActive = this.params.enableDotScreen;
                    break;
                case 'glitch':
                    isActive = this.params.enableGlitch;
                    break;
                case 'halftone':
                    isActive = this.params.enableHalftone;
                    break;
                case 'outline':
                    isActive = this.params.enableOutline;
                    break;
                case 'fxaa':
                    isActive = this.params.enableFXAA;
                    break;
                case 'output':
                    isActive = true; // 总是激活
                    break;
            }
            
            item.classList.toggle('active', isActive);
        });
    }
    
    updateResolution() {
        const width = window.innerWidth * this.params.resolution;
        const height = window.innerHeight * this.params.resolution;
        
        this.composer.setSize(width, height);
        this.fxaaPass.uniforms['resolution'].value.set(1 / width, 1 / height);
    }
    
    resetAllEffects() {
        // 重置所有参数到默认值
        this.params = {
            enablePostProcessing: true,
            resolution: 1.0,
            enableBloom: true,
            bloomStrength: 1.5,
            bloomRadius: 0.4,
            bloomThreshold: 0.85,
            enableFilm: false,
            filmNoise: 0.35,
            filmScanline: 0.025,
            filmGrayscale: false,
            enableColorCorrection: false,
            brightness: 1.0,
            contrast: 1.0,
            saturation: 1.0,
            enableFXAA: true,
            autoRotate: true,
            rotationSpeed: 0.01,
            enablePixelated: false,
            pixelSize: 6,
            enableDotScreen: false,
            dotScreenScale: 4.0,
            dotScreenAngle: 1.57,
            enableGlitch: false,
            glitchWildness: 0.2,
            enableHalftone: false,
            halftoneRadius: 4.0,
            halftoneScatter: 0.0,
            enableOutline: false,
            outlineEdgeStrength: 3.0,
            outlineEdgeGlow: 0.0,
            outlineEdgeThickness: 1.0,
            outlinePulsePeriod: 0.0,
            outlineVisibleEdgeColor: new THREE.Color(0xffffff),
            outlineHiddenEdgeColor: new THREE.Color(0x190a05)
        };
        
        // 更新UI控件
        document.getElementById('enablePostProcessing').checked = this.params.enablePostProcessing;
        document.getElementById('resolution').value = this.params.resolution;
        document.getElementById('enableBloom').checked = this.params.enableBloom;
        document.getElementById('bloomStrength').value = this.params.bloomStrength;
        document.getElementById('bloomRadius').value = this.params.bloomRadius;
        document.getElementById('bloomThreshold').value = this.params.bloomThreshold;
        document.getElementById('enableFilm').checked = this.params.enableFilm;
        document.getElementById('filmNoise').value = this.params.filmNoise;
        document.getElementById('filmScanline').value = this.params.filmScanline;
        document.getElementById('filmGrayscale').checked = this.params.filmGrayscale;
        document.getElementById('enableColorCorrection').checked = this.params.enableColorCorrection;
        document.getElementById('brightness').value = this.params.brightness;
        document.getElementById('contrast').value = this.params.contrast;
        document.getElementById('saturation').value = this.params.saturation;
        document.getElementById('enableFXAA').checked = this.params.enableFXAA;
        document.getElementById('autoRotate').checked = this.params.autoRotate;
        document.getElementById('rotationSpeed').value = this.params.rotationSpeed;
        document.getElementById('enablePixelated').checked = this.params.enablePixelated;
        document.getElementById('pixelSize').value = this.params.pixelSize;
        document.getElementById('enableDotScreen').checked = this.params.enableDotScreen;
        document.getElementById('dotScreenScale').value = this.params.dotScreenScale;
        document.getElementById('dotScreenAngle').value = this.params.dotScreenAngle;
        document.getElementById('enableGlitch').checked = this.params.enableGlitch;
        document.getElementById('glitchWildness').value = this.params.glitchWildness;
        document.getElementById('enableHalftone').checked = this.params.enableHalftone;
        document.getElementById('halftoneRadius').value = this.params.halftoneRadius;
        document.getElementById('halftoneScatter').value = this.params.halftoneScatter;
        document.getElementById('enableOutline').checked = this.params.enableOutline;
        document.getElementById('outlineEdgeStrength').value = this.params.outlineEdgeStrength;
        document.getElementById('outlineEdgeGlow').value = this.params.outlineEdgeGlow;
        document.getElementById('outlineEdgeThickness').value = this.params.outlineEdgeThickness;
        document.getElementById('outlinePulsePeriod').value = this.params.outlinePulsePeriod;
        document.getElementById('outlineVisibleEdgeColor').value = '#' + this.params.outlineVisibleEdgeColor.getHexString();
        document.getElementById('outlineHiddenEdgeColor').value = '#' + this.params.outlineHiddenEdgeColor.getHexString();
        
        // 更新显示值
        document.getElementById('bloomStrengthValue').textContent = this.params.bloomStrength;
        document.getElementById('bloomRadiusValue').textContent = this.params.bloomRadius;
        document.getElementById('bloomThresholdValue').textContent = this.params.bloomThreshold;
        document.getElementById('filmNoiseValue').textContent = this.params.filmNoise;
        document.getElementById('filmScanlineValue').textContent = this.params.filmScanline;
        document.getElementById('brightnessValue').textContent = this.params.brightness;
        document.getElementById('contrastValue').textContent = this.params.contrast;
        document.getElementById('saturationValue').textContent = this.params.saturation;
        document.getElementById('rotationSpeedValue').textContent = this.params.rotationSpeed;
        document.getElementById('pixelSizeValue').textContent = this.params.pixelSize;
        document.getElementById('dotScreenScaleValue').textContent = this.params.dotScreenScale.toFixed(1);
        document.getElementById('dotScreenAngleValue').textContent = this.params.dotScreenAngle.toFixed(2);
        document.getElementById('glitchWildnessValue').textContent = this.params.glitchWildness.toFixed(2);
        document.getElementById('halftoneRadiusValue').textContent = this.params.halftoneRadius.toFixed(1);
        document.getElementById('halftoneScatterValue').textContent = this.params.halftoneScatter.toFixed(2);
        document.getElementById('outlineEdgeStrengthValue').textContent = this.params.outlineEdgeStrength.toFixed(1);
        document.getElementById('outlineEdgeGlowValue').textContent = this.params.outlineEdgeGlow.toFixed(1);
        document.getElementById('outlineEdgeThicknessValue').textContent = this.params.outlineEdgeThickness.toFixed(1);
        document.getElementById('outlinePulsePeriodValue').textContent = this.params.outlinePulsePeriod.toFixed(1);
        
        // 更新后处理效果
        this.bloomPass.enabled = this.params.enableBloom;
        this.bloomPass.strength = this.params.bloomStrength;
        this.bloomPass.radius = this.params.bloomRadius;
        this.bloomPass.threshold = this.params.bloomThreshold;
        
        this.filmPass.enabled = this.params.enableFilm;
        this.filmPass.uniforms.nIntensity.value = this.params.filmNoise;
        this.filmPass.uniforms.sIntensity.value = this.params.filmScanline;
        this.filmPass.uniforms.grayscale.value = this.params.filmGrayscale;
        
        this.colorCorrectionPass.enabled = this.params.enableColorCorrection;
        this.colorCorrectionPass.uniforms.brightness.value = this.params.brightness;
        this.colorCorrectionPass.uniforms.contrast.value = this.params.contrast;
        this.colorCorrectionPass.uniforms.saturation.value = this.params.saturation;
        
        this.fxaaPass.enabled = this.params.enableFXAA;
        
        this.pixelatedPass.enabled = this.params.enablePixelated;
        this.pixelatedPass.setPixelSize(this.params.pixelSize);
        
        this.dotScreenPass.enabled = this.params.enableDotScreen;
        this.dotScreenPass.uniforms.scale.value = this.params.dotScreenScale;
        this.dotScreenPass.uniforms.angle.value = this.params.dotScreenAngle;
        
        this.glitchPass.enabled = this.params.enableGlitch;
        // Note: Standard GlitchPass doesn't have wildness uniform
        if (this.glitchPass.uniforms && this.glitchPass.uniforms.wildness) {
            this.glitchPass.uniforms.wildness.value = this.params.glitchWildness;
        }
        
        this.halftonePass.enabled = this.params.enableHalftone;
        this.halftonePass.uniforms.radius.value = this.params.halftoneRadius;
        this.halftonePass.uniforms.scatter.value = this.params.halftoneScatter;
        
        this.outlinePass.enabled = this.params.enableOutline;
        this.outlinePass.edgeStrength = this.params.outlineEdgeStrength;
        this.outlinePass.edgeGlow = this.params.outlineEdgeGlow;
        this.outlinePass.edgeThickness = this.params.outlineEdgeThickness;
        this.outlinePass.pulsePeriod = this.params.outlinePulsePeriod;
        this.outlinePass.visibleEdgeColor.copy(this.params.outlineVisibleEdgeColor);
        this.outlinePass.hiddenEdgeColor.copy(this.params.outlineHiddenEdgeColor);
        
        this.updateResolution();
        this.updateEffectChain();
    }
    
    updatePerformanceStats() {
        const currentTime = performance.now();
        this.stats.frameCount++;
        
        if (currentTime - this.stats.lastTime >= 1000) {
            this.stats.fps = Math.round((this.stats.frameCount * 1000) / (currentTime - this.stats.lastTime));
            this.stats.frameTime = (currentTime - this.stats.lastTime) / this.stats.frameCount;
            
            document.getElementById('fps').textContent = this.stats.fps;
            document.getElementById('renderTime').textContent = this.stats.frameTime.toFixed(1) + 'ms';
            
            this.stats.frameCount = 0;
            this.stats.lastTime = currentTime;
        }
    }
    
    setupPassInfoListeners() {
        // 为效果链中的每个通道添加点击事件
        const effectItems = document.querySelectorAll('.effect-item');
        effectItems.forEach(item => {
            item.addEventListener('click', () => {
                const passType = item.dataset.effect;
                this.selectPass(passType);
            });
        });
    }
    
    selectPass(passType) {
        // 更新选中状态
        document.querySelectorAll('.effect-item').forEach(item => {
            item.classList.remove('selected');
        });
        
        const selectedItem = document.querySelector(`[data-effect="${passType}"]`);
        if (selectedItem) {
            selectedItem.classList.add('selected');
        }
        
        this.currentSelectedPass = passType;
        this.updatePassInfo(passType);
    }
    
    updatePassInfo(passType) {
        const passData = this.passInfoData[passType];
        if (!passData) return;
        
        // 更新通道名称和状态
        document.getElementById('currentPassName').textContent = passData.name;
        const statusElement = document.getElementById('currentPassStatus');
        
        // 根据通道类型和当前设置确定状态
        let isActive = true;
        let statusText = '激活';
        let statusClass = 'active';
        
        switch(passType) {
            case 'bloom':
                isActive = this.params.enableBloom;
                break;
            case 'film':
                isActive = this.params.enableFilm;
                break;
            case 'color':
                isActive = this.params.enableColorCorrection;
                break;
            case 'pixelated':
                isActive = this.params.enablePixelated;
                break;
            case 'dotscreen':
                isActive = this.params.enableDotScreen;
                break;
            case 'glitch':
                isActive = this.params.enableGlitch;
                break;
            case 'halftone':
                isActive = this.params.enableHalftone;
                break;
            case 'fxaa':
                isActive = this.params.enableFXAA;
                break;
            case 'render':
            case 'output':
                isActive = true;
                break;
        }
        
        if (!isActive) {
            statusText = '未激活';
            statusClass = 'inactive';
        }
        
        statusElement.textContent = statusText;
        statusElement.className = `pass-status ${statusClass}`;
        
        // 更新描述
        document.getElementById('passDescription').textContent = passData.description;
        
        // 更新属性列表
        const propertiesContainer = document.getElementById('passProperties');
        propertiesContainer.innerHTML = '';
        
        // 检查是否有新的属性格式
        if (passData.usage && passData.usage.properties) {
            // 新格式：显示属性说明
            passData.usage.properties.forEach(prop => {
                const propertyItem = document.createElement('div');
                propertyItem.className = 'property-item';
                propertyItem.innerHTML = `<span class="property-desc">${prop}</span>`;
                propertiesContainer.appendChild(propertyItem);
            });
        } else {
            // 旧格式：显示动态属性值
            Object.entries(passData.properties).forEach(([key, prop]) => {
                const propertyItem = document.createElement('div');
                propertyItem.className = 'property-item';
                
                let value = prop.value;
                if (value === 'dynamic') {
                    // 根据通道类型获取动态值
                    value = this.getDynamicPropertyValue(passType, key);
                }
                
                propertyItem.innerHTML = `
                    <span class="property-name">${key}</span>
                    <span class="property-value">${value}</span>
                    <span class="property-desc">${prop.desc}</span>
                `;
                
                propertiesContainer.appendChild(propertyItem);
            });
        }
        
        // 更新参数列表
        const parametersContainer = document.getElementById('passParameters');
        parametersContainer.innerHTML = '';
        
        // 检查是否有新的参数格式
        if (passData.usage && passData.usage.parameters) {
            // 新格式：显示参数说明
            passData.usage.parameters.forEach(param => {
                const parameterItem = document.createElement('div');
                parameterItem.className = 'parameter-item';
                parameterItem.innerHTML = `<span class="param-desc">${param}</span>`;
                parametersContainer.appendChild(parameterItem);
            });
        } else {
            // 旧格式：显示动态参数值
            Object.entries(passData.parameters).forEach(([key, value]) => {
                const parameterItem = document.createElement('div');
                parameterItem.className = 'parameter-item';
                
                let paramValue = value;
                if (value === 'dynamic') {
                    paramValue = this.getDynamicParameterValue(passType, key);
                }
                
                parameterItem.innerHTML = `
                    <span class="param-name">${key}</span>
                    <span class="param-value">${paramValue}</span>
                `;
                
                parametersContainer.appendChild(parameterItem);
            });
        }
        
        // 更新使用说明
        let usageHTML = `<p>${passData.usage.description}</p>`;
        
        // 检查是否有新的代码格式
        if (passData.usage.code && Array.isArray(passData.usage.code)) {
            // 新格式：显示代码数组
            usageHTML += `
                <h4>代码示例</h4>
                <pre><code>${passData.usage.code.join('\n')}</code></pre>
            `;
        } else if (passData.usage.code) {
            // 旧格式：显示单行代码
            usageHTML += `<code>${passData.usage.code}</code>`;
        }
        
        // 添加详细说明（向后兼容）
        if (passData.usage.details) {
            usageHTML += `
                <h4>详细说明</h4>
                <ul class="usage-details">
                    ${passData.usage.details.map(detail => `<li>${detail}</li>`).join('')}
                </ul>
            `;
        }
        
        // 添加使用技巧（向后兼容）
        if (passData.usage.tips) {
            usageHTML += `
                <h4>使用技巧</h4>
                <ul class="usage-tips">
                    ${passData.usage.tips.map(tip => `<li>${tip}</li>`).join('')}
                </ul>
            `;
        }
        
        // 添加常见问题（向后兼容）
        if (passData.usage.issues) {
            usageHTML += `
                <h4>常见问题</h4>
                <ul class="usage-issues">
                    ${passData.usage.issues.map(issue => `<li>${issue}</li>`).join('')}
                </ul>
            `;
        }
        
        document.getElementById('passUsage').innerHTML = usageHTML;
    }
    
    getDynamicPropertyValue(passType, property) {
        switch(passType) {
            case 'bloom':
                if (property === 'enabled') return this.params.enableBloom.toString();
                break;
            case 'film':
                if (property === 'enabled') return this.params.enableFilm.toString();
                break;
            case 'color':
                if (property === 'enabled') return this.params.enableColorCorrection.toString();
                break;
            case 'pixelated':
                if (property === 'enabled') return this.params.enablePixelated.toString();
                break;
            case 'dotscreen':
                if (property === 'enabled') return this.params.enableDotScreen.toString();
                break;
            case 'glitch':
                if (property === 'enabled') return this.params.enableGlitch.toString();
                break;
            case 'halftone':
                if (property === 'enabled') return this.params.enableHalftone.toString();
                break;
            case 'outline':
                if (property === 'enabled') return this.params.enableOutline.toString();
                break;
            case 'fxaa':
                if (property === 'enabled') return this.params.enableFXAA.toString();
                break;
        }
        return 'true';
    }
    
    getDynamicParameterValue(passType, parameter) {
        switch(passType) {
            case 'bloom':
                if (parameter === 'strength') return this.params.bloomStrength.toFixed(2);
                if (parameter === 'radius') return this.params.bloomRadius.toFixed(2);
                if (parameter === 'threshold') return this.params.bloomThreshold.toFixed(2);
                break;
            case 'film':
                if (parameter === 'noiseIntensity') return this.params.filmNoise.toFixed(2);
                if (parameter === 'scanlinesIntensity') return this.params.filmScanline.toFixed(3);
                if (parameter === 'grayscale') return this.params.filmGrayscale.toString();
                break;
            case 'color':
                 if (parameter === 'brightness') return this.params.colorBrightness.toFixed(2);
                 if (parameter === 'contrast') return this.params.colorContrast.toFixed(2);
                 if (parameter === 'saturation') return this.params.colorSaturation.toFixed(2);
                 if (parameter === 'hue') return this.params.colorHue.toFixed(2);
                 break;
            case 'pixelated':
                if (parameter === 'pixelSize') return this.params.pixelSize.toString();
                break;
            case 'dotscreen':
                if (parameter === 'scale') return this.params.dotScreenScale.toFixed(2);
                if (parameter === 'angle') return this.params.dotScreenAngle.toFixed(2);
                break;
            case 'glitch':
                if (parameter === 'wildness') return this.params.glitchWildness.toFixed(2);
                break;
            case 'halftone':
                if (parameter === 'radius') return this.params.halftoneRadius.toFixed(2);
                if (parameter === 'scatter') return this.params.halftoneScatter.toFixed(2);
                break;
            case 'outline':
                if (parameter === 'edgeStrength') return (this.params.outlineEdgeStrength !== undefined ? this.params.outlineEdgeStrength.toFixed(2) : '0.00');
                if (parameter === 'edgeGlow') return (this.params.outlineEdgeGlow !== undefined ? this.params.outlineEdgeGlow.toFixed(2) : '0.00');
                if (parameter === 'edgeThickness') return (this.params.outlineEdgeThickness !== undefined ? this.params.outlineEdgeThickness.toFixed(2) : '0.00');
                if (parameter === 'pulsePeriod') return (this.params.outlinePulsePeriod !== undefined ? this.params.outlinePulsePeriod.toFixed(2) : '0.00');
                if (parameter === 'visibleEdgeColor') return (this.params.outlineVisibleEdgeColor ? `rgb(${Math.round(this.params.outlineVisibleEdgeColor.r * 255)}, ${Math.round(this.params.outlineVisibleEdgeColor.g * 255)}, ${Math.round(this.params.outlineVisibleEdgeColor.b * 255)})` : 'rgb(255, 255, 255)');
                if (parameter === 'hiddenEdgeColor') return (this.params.outlineHiddenEdgeColor ? `rgb(${Math.round(this.params.outlineHiddenEdgeColor.r * 255)}, ${Math.round(this.params.outlineHiddenEdgeColor.g * 255)}, ${Math.round(this.params.outlineHiddenEdgeColor.b * 255)})` : 'rgb(25, 10, 5)');
                break;
        }
        return 'N/A';
    }
    
    onWindowResize() {
        this.camera.aspect = window.innerWidth / window.innerHeight;
        this.camera.updateProjectionMatrix();
        
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.composer.setSize(
            window.innerWidth * this.params.resolution,
            window.innerHeight * this.params.resolution
        );
        
        this.fxaaPass.uniforms['resolution'].value.set(
            1 / (window.innerWidth * this.params.resolution),
            1 / (window.innerHeight * this.params.resolution)
        );
    }
    
    animate() {
        requestAnimationFrame(() => this.animate());
        
        // 更新控制器
        this.controls.update();
        
        // 自动旋转物体
        if (this.params.autoRotate) {
            this.meshes.forEach((mesh, index) => {
                mesh.rotation.x += this.params.rotationSpeed * (1 + index * 0.1);
                mesh.rotation.y += this.params.rotationSpeed * (1 + index * 0.2);
            });
            
            // 旋转点光源
            this.lights.points.forEach((light, index) => {
                const time = Date.now() * 0.001;
                const angle = (index / 5) * Math.PI * 2 + time * 0.5;
                light.position.x = Math.cos(angle) * 8;
                light.position.z = Math.sin(angle) * 8;
                light.position.y = Math.sin(time + index) * 3 + 2;
            });
        }
        
        // 更新胶片效果时间
        if (this.filmPass.enabled) {
            this.filmPass.uniforms.time.value += 0.01;
        }
        
        // 渲染
        if (this.params.enablePostProcessing) {
            this.composer.render();
        } else {
            this.renderer.render(this.scene, this.camera);
        }
        
        // 更新性能统计
        this.updatePerformanceStats();
    }
}

// 初始化演示
window.addEventListener('DOMContentLoaded', () => {
    new PostProcessingDemo();
});

// 弹窗模态框功能
function openCodeModal() {
    const modal = document.getElementById('codeModal');
    modal.style.display = 'block';
    document.body.style.overflow = 'hidden'; // 防止背景滚动
}

function closeCodeModal() {
    const modal = document.getElementById('codeModal');
    modal.style.display = 'none';
    document.body.style.overflow = 'auto'; // 恢复背景滚动
}

// 将函数添加到全局作用域
window.openCodeModal = openCodeModal;
window.closeCodeModal = closeCodeModal;
window.copyModalCode = copyModalCode;

// 复制模态框中的代码
function copyModalCode() {
    const codeElement = document.getElementById('modal-complete-code');
    const copyBtn = document.querySelector('.modal-copy-btn');
    
    if (navigator.clipboard && window.isSecureContext) {
        navigator.clipboard.writeText(codeElement.textContent).then(() => {
            const originalText = copyBtn.textContent;
            copyBtn.textContent = '✅ 已复制';
            copyBtn.style.background = 'linear-gradient(45deg, #4CAF50, #45a049)';
            
            setTimeout(() => {
                copyBtn.textContent = originalText;
                copyBtn.style.background = 'linear-gradient(45deg, #4CAF50, #45a049)';
            }, 2000);
        }).catch(err => {
            console.error('复制失败:', err);
            fallbackCopyModalCode(codeElement.textContent, copyBtn);
        });
    } else {
        fallbackCopyModalCode(codeElement.textContent, copyBtn);
    }
}

// 模态框复制降级方案
function fallbackCopyModalCode(text, copyBtn) {
    const textArea = document.createElement('textarea');
    textArea.value = text;
    textArea.style.position = 'fixed';
    textArea.style.left = '-999999px';
    textArea.style.top = '-999999px';
    document.body.appendChild(textArea);
    textArea.focus();
    textArea.select();
    
    try {
        const successful = document.execCommand('copy');
        if (successful) {
            const originalText = copyBtn.textContent;
            copyBtn.textContent = '✅ 已复制';
            copyBtn.style.background = 'linear-gradient(45deg, #4CAF50, #45a049)';
            
            setTimeout(() => {
                copyBtn.textContent = originalText;
                copyBtn.style.background = 'linear-gradient(45deg, #4CAF50, #45a049)';
            }, 2000);
        } else {
            throw new Error('execCommand failed');
        }
    } catch (err) {
        console.error('降级复制也失败了:', err);
        alert('复制功能不可用，请手动选择代码并复制');
    }
    
    document.body.removeChild(textArea);
}

// 点击模态框外部关闭
window.onclick = function(event) {
    const modal = document.getElementById('codeModal');
    if (event.target === modal) {
        closeCodeModal();
    }
}

// ESC键关闭模态框
document.addEventListener('keydown', function(event) {
    if (event.key === 'Escape') {
        const modal = document.getElementById('codeModal');
        if (modal.style.display === 'block') {
            closeCodeModal();
        }
    }
});

// 复制代码到剪贴板功能（原有功能保持不变）
function copyCodeToClipboard() {
    const codeElement = document.getElementById('complete-code');
    const copyBtn = document.querySelector('.copy-btn');
    
    if (navigator.clipboard && window.isSecureContext) {
        navigator.clipboard.writeText(codeElement.textContent).then(() => {
            const originalText = copyBtn.textContent;
            copyBtn.textContent = '✅ 已复制';
            copyBtn.style.background = 'linear-gradient(45deg, #4CAF50, #45a049)';
            
            setTimeout(() => {
                copyBtn.textContent = originalText;
                copyBtn.style.background = 'linear-gradient(45deg, #667eea, #764ba2)';
            }, 2000);
        }).catch(err => {
            console.error('复制失败:', err);
            fallbackCopyTextToClipboard(codeElement.textContent, copyBtn);
        });
    } else {
        fallbackCopyTextToClipboard(codeElement.textContent, copyBtn);
    }
}

// 降级复制方案
function fallbackCopyTextToClipboard(text, copyBtn) {
    const textArea = document.createElement('textarea');
    textArea.value = text;
    textArea.style.position = 'fixed';
    textArea.style.left = '-999999px';
    textArea.style.top = '-999999px';
    document.body.appendChild(textArea);
    textArea.focus();
    textArea.select();
    
    try {
        const successful = document.execCommand('copy');
        if (successful) {
            const originalText = copyBtn.textContent;
            copyBtn.textContent = '✅ 已复制';
            copyBtn.style.background = 'linear-gradient(45deg, #4CAF50, #45a049)';
            
            setTimeout(() => {
                copyBtn.textContent = originalText;
                copyBtn.style.background = 'linear-gradient(45deg, #667eea, #764ba2)';
            }, 2000);
        } else {
            throw new Error('execCommand failed');
        }
    } catch (err) {
        console.error('降级复制也失败了:', err);
        alert('复制功能不可用，请手动选择代码并复制');
    }
    
    document.body.removeChild(textArea);
}